﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Net;
using System.IO;
using System.Windows.Forms;

namespace ConnectionAnalyzer
{
    public static class Settings
    {
        public static string Domain = "facebook";//"fa-ir.lisp4.facebook";
    }

    public class CookieManager
    {
        public CookieManager() { }

        public CookieManager(string cookieString)
        {
            Regex valid = new Regex(@"\[(?:\{(?:.*?),(?:.*?)\}, )*(?:\{(?:.*?),(?:.*?)\})\]");
            Regex cookies = new Regex(@"\{(?<key>.*?),(?<val>.*?)\}");

            if (!valid.IsMatch(cookieString))
                return;

            foreach (var cookie in cookies.Matches(cookieString).Cast<Match>())
            {
                string key = cookie.Groups["key"].Value;
                string value = cookie.Groups["val"].Value;

                if (key != null && value != null)
                {
                    this.CookieValues[key] = value;
                }
            }
        }
        private Dictionary<string, string> cookieValues;

        public Dictionary<string, string> CookieValues
        {
            get
            {
                if (this.cookieValues == null)
                {
                    this.cookieValues = new Dictionary<string, string>();
                }

                return this.cookieValues;
            }
        }

        public void PublishCookies(HttpWebRequest webRequest)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Cookie: ");
            foreach (string key in this.CookieValues.Keys)
            {
                sb.Append(key);
                sb.Append("=");
                sb.Append(this.CookieValues[key]);
                sb.Append("; ");
                sb.Append("$Path=\"/\"; ");
            }

            webRequest.Headers.Add(sb.ToString());
            sb = null;
            webRequest = null;
        }

        public void StoreCookies(HttpWebResponse webResponse)
        {
            for (int x = 0; x < webResponse.Headers.Count; x++)
            {
                if (webResponse.Headers.Keys[x].ToLower().Equals("set-cookie"))
                {
                    this.AddRawCookie(webResponse.Headers[x]);
                }
            }

            webResponse = null;
        }

        private void AddRawCookie(string rawCookieData)
        {
            string key = null;
            string value = null;

            string[] entries = null;

            if (rawCookieData.IndexOf(",") > 0)
            {
                entries = rawCookieData.Split(',');
            }
            else
            {
                entries = new string[] { rawCookieData };
            }

            foreach (string entry in entries)
            {
                string cookieData = entry.Trim();

                if (cookieData.IndexOf(';') > 0)
                {
                    string[] temp = cookieData.Split(';');
                    cookieData = temp[0];
                }

                int index = cookieData.IndexOf('=');
                if (index > 0)
                {
                    key = cookieData.Substring(0, index);
                    value = cookieData.Substring(index + 1);
                }

                if (key != null && value != null)
                {
                    this.CookieValues[key] = value;
                }

                cookieData = null;
            }

            rawCookieData = null;
            entries = null;
            key = null;
            value = null;
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("[");
            foreach (string key in this.CookieValues.Keys)
            {
                sb.Append("{");
                sb.Append(key);
                sb.Append(",");
                sb.Append(this.CookieValues[key]);
                sb.Append("}, ");
            }
            if (this.CookieValues.Keys.Count > 0)
            {
                sb.Remove(sb.Length - 2, 2);
            }
            sb.Append("]");

            return sb.ToString();
        }
    }

    public enum HttpVerb
    {
        GET,
        POST,
        DELETE
    }
    public class WebDownloader
    {
        public static TextBox tbOutPut { get; set; }
        private static string userAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; InfoPath.2; MS-RTC LM 8; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E)";

        public static Int32 LoginTimeOut = 60000; // one minute 

        public static string PostData(string url, string poststring)
        {
            CookieManager cookieManager = new CookieManager();
            return PostData(url, poststring, cookieManager);
        }

        private static void mark(string p, string p2)
        {
            tbOutPut.Text += "================\n" + p + "================\n\n";
            output(p2);
            Application.DoEvents();
        }

        private static void output(string p)
        {
            tbOutPut.Text += p;
        }
        
        public static string PostData(string url, string poststring, CookieManager cookieManager)
        {
            if (string.IsNullOrEmpty(poststring))
                return null;

            HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
            cookieManager.PublishCookies(httpRequest);

            httpRequest.Method = "POST";
            httpRequest.ContentType = "application/x-www-form-urlencoded";
            httpRequest.UserAgent = userAgent;
            httpRequest.AllowAutoRedirect = true;
            httpRequest.AllowWriteStreamBuffering = true;
            httpRequest.Proxy = null;

            byte[] bytedata = Encoding.UTF8.GetBytes(poststring);
            httpRequest.ContentLength = bytedata.Length;

            Stream requestStream = httpRequest.GetRequestStream();
            requestStream.Write(bytedata, 0, bytedata.Length);
            requestStream.Close();


            HttpWebResponse httpWebResponse = null;

            try
            {
                httpWebResponse = (HttpWebResponse)httpRequest.GetResponse();
            }
            catch (WebException ex)
            {
                mark("PostData Exception", ex.Message);
                mark("PostData Exception StackTrace", ex.StackTrace);
            }

            if (httpWebResponse != null)
                cookieManager.StoreCookies(httpWebResponse);
            else
                return "";

            string ret = "";
            Stream dataStream = httpWebResponse.GetResponseStream();
            StreamReader reader = new StreamReader(dataStream);

            ret = reader.ReadToEnd();
            return ret;
        }

        public static HttpWebResponse GetRawResponse(string url, CookieManager cookieManager)
        {
            try
            {
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
                request.UserAgent = userAgent;
                request.Timeout = LoginTimeOut / 4;
                request.Method = "GET";
                request.Proxy = null;
                cookieManager.PublishCookies(request);

                return (HttpWebResponse)request.GetResponse();

            }
            catch (Exception e)
            {
                mark("GetRawResponse Exception", e.Message);
                mark("GetRawResponse Exception StackTrace", e.StackTrace);
                try
                {
                    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
                    request.UserAgent = userAgent;
                    request.Timeout = LoginTimeOut;
                    request.Method = "GET";
                    cookieManager.PublishCookies(request);

                    return (HttpWebResponse)request.GetResponse();

                }
                catch (Exception ex)
                {
                    mark("GetRawResponse Exception", ex.Message);
                    mark("GetRawResponse Exception StackTrace", ex.StackTrace);
                }

            }

            return null;
        }

        /// <summary>
        /// Downloads a JSON string from a given URL.
        /// </summary>
        /// <param name="url">The URL for the JSON object.</param>
        /// <returns>A string in JSON notation.</returns>
        public static string DownloadJSON(string url)
        {
            return DownloadJSON(url, new CookieManager());
        }

        public static string DownloadJSON(string url, CookieManager cookieManager)
        {
            string ret = "";
            try
            {
                HttpWebResponse response = GetRawResponse(url, cookieManager);

                if (response != null)
                    cookieManager.StoreCookies(response);
                Stream dataStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(dataStream);

                ret = reader.ReadToEnd();

                reader.Close();
                dataStream.Close();
                response.Close();
            }
            catch (Exception ex)
            {
                mark("DownloadJSON Exception", ex.Message);
                mark("DownloadJSON Exception StackTrace", ex.StackTrace);
            }

            return ret;
        }

        public static string DownloadHTML(string url)
        {
            return DownloadJSON(url, new CookieManager());
        }

        public static string DownloadHTML(string url, CookieManager cookieManager)
        {
            return DownloadJSON(url, cookieManager);
        }

        public static bool DownloadImageFile(string filePath, string url)
        {
            FileStream fsFileStream = null;
            HttpWebRequest webRequest = null;
            HttpWebResponse webResponse = null;
            bool ret = false;

            try
            {
                byte[] BUFFER = new byte[307200]; // 300 KB
                webRequest = (HttpWebRequest)WebRequest.Create(url);
                webRequest.Method = "GET";
                webRequest.Timeout = 120000;
                webResponse = (HttpWebResponse)webRequest.GetResponse(); //Getting the response

                if (webResponse.StatusCode.ToString().Equals("OK"))
                {
                    Stream responseStream = webResponse.GetResponseStream();
                    Stream ToStream = null;

                    try
                    {
                        if (File.Exists(filePath))
                        {
                            File.Delete(filePath);
                        }

                        ToStream = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write);

                        int count = 1;

                        while (count != 0)
                        {
                            count = responseStream.Read(BUFFER, 0, BUFFER.Length);
                            ToStream.Write(BUFFER, 0, count);
                            ToStream.Flush();
                        }

                        ret = true;
                    }
                    catch (Exception exception)
                    {
                        mark("DownloadImageFile Exception", exception.Message);
                        mark("DownloadImageFile Exception StackTrace", exception.StackTrace);
                    }
                    finally
                    {
                        ToStream.Close();
                        ToStream = null;
                    }
                }
            }
            catch (Exception exp)
            {
                mark("DownloadImageFile Exception", exp.Message);
                mark("DownloadImageFile Exception StackTrace", exp.StackTrace);
            }
            finally
            {
                if (fsFileStream != null)
                {
                    //Closing file stream
                    fsFileStream.Close();
                    fsFileStream = null;
                }
                if (webRequest != null)
                {
                    webRequest = null;
                }
                if (webResponse != null)
                {
                    webResponse.Close();
                    webResponse = null;
                }
            }

            return ret;
        }

        public static Stream DownloadImageFile(string url)
        {
            FileStream fsFileStream = null;
            HttpWebRequest webRequest = null;
            HttpWebResponse webResponse = null;
            Stream responseStream = null;

            try
            {
                byte[] BUFFER = new byte[307200]; // 300 KB
                webRequest = (HttpWebRequest)WebRequest.Create(url);
                webRequest.Method = "GET";
                webRequest.Timeout = 120000;
                webResponse = (HttpWebResponse)webRequest.GetResponse(); //Getting the response

                if (webResponse.StatusCode.ToString().Equals("OK"))
                {
                    responseStream = webResponse.GetResponseStream();
                }
            }
            catch (Exception exp) { }
            finally
            {
                if (fsFileStream != null)
                {
                    //Closing file stream
                    fsFileStream.Close();
                    fsFileStream = null;
                }
                if (webRequest != null)
                {
                    webRequest = null;
                }
                if (webResponse != null)
                {
                    webResponse.Close();
                    webResponse = null;
                }
            }

            return responseStream;
        }

        public static string MakeRequest(Uri url, HttpVerb httpVerb, Dictionary<string, string> args)
        {
            if (args != null && args.Keys.Count > 0 && httpVerb == HttpVerb.GET)
            {
                url = new Uri(url.ToString() + EncodeDictionary(args, true));
            }
            if (args == null)
                args = new Dictionary<string, string>();

            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            request.Method = httpVerb.ToString();
            request.UserAgent = userAgent;

            if (httpVerb == HttpVerb.POST || httpVerb == HttpVerb.DELETE)
            {
                string postData = EncodeDictionary(args, false);
                ASCIIEncoding encoding = new ASCIIEncoding();

                byte[] postDataBytes = encoding.GetBytes(postData);
                request.ContentType = "application/x-www-form-urlencoded";
                request.ContentLength = postDataBytes.Length;
                request.Accept = @"image/gif, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/vnd.xfdl; version=""6.5.0"", application/x-shockwave-flash, */*";
                request.Method = httpVerb.ToString();
                request.KeepAlive = true;
                request.ProtocolVersion = new Version(1, 1);
                request.Headers.Add("Accept-Language: en-us");
                request.Headers.Add("Accept-Encoding: gzip, deflate");
                request.Headers.Add("Cache-Control: no-cache");
                Stream requestStream = request.GetRequestStream();
                requestStream.Write(postDataBytes, 0, postDataBytes.Length);
                requestStream.Close();
            }

            try
            {
                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                    StreamReader reader = new StreamReader(response.GetResponseStream());
                    return reader.ReadToEnd();
                }
            }
            catch (WebException e)
            {
                string error = new StreamReader(e.Response.GetResponseStream()).ReadToEnd();
                return error;
            }
        }

        private static string EncodeDictionary(Dictionary<string, string> dict, bool questionMark)
        {
            StringBuilder sb = new StringBuilder();
            if (questionMark)
            {
                sb.Append("?");
            }
            foreach (KeyValuePair<string, string> kvp in dict)
            {
                sb.Append(HttpUtility.UrlEncode(kvp.Key));
                sb.Append("="); sb.Append(HttpUtility.UrlEncode(kvp.Value));
                sb.Append("&");
            }

            sb.Remove(sb.Length - 1, 1);
            return sb.ToString();
        }
    }

}
